﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Reflection;
using Paint;
using System.Globalization;
using System.Threading;
using System.Collections;

namespace Paint
{
    public partial class Paint : Form
    {
        public const int GRID_SIZE = 10;
        private List<LineSize> lineSizes = new List<LineSize>(4);
        private List<LineStyle> lineStyles = new List<LineStyle>(4);
        private List<FillStyle> fillStyles = new List<FillStyle>(Enum.GetValues(typeof(HatchStyle)).Length);
        private List<Drawable> shapes = new List<Drawable>();
        private List<Drawable> shapesBuffer = new List<Drawable>();
        private PaintContext paintContext = new PaintContext();
        private Drawable selectedFigure;
        private ITextPlugin textPlugin;
        private bool drawing;
        private bool textDrawing;

        public Paint()
        {
            InitializeComponent();

            lineSizes.Add(new LineSize("1px", Properties.Resources.line_1px, 1));
            lineSizes.Add(new LineSize("3px", Properties.Resources.line_3px, 3));
            lineSizes.Add(new LineSize("5px", Properties.Resources.line_5px, 5));
            lineSizes.Add(new LineSize("8px", Properties.Resources.line_8px, 8));
            foreach (var item in lineSizes)
	        {
                sizeCmbx.Items.Add(item.Name);
	        }

            foreach (DashStyle item in Enum.GetValues(typeof(DashStyle)))
            {
                if (item.Equals(DashStyle.Custom)) continue;
                Bitmap lineStyleBmp = new Bitmap(100, 30);
                Graphics lineStyleGraphics = Graphics.FromImage(lineStyleBmp);
                Pen pen = new Pen(Color.Red, 6);
                pen.DashStyle = item;
                lineStyleGraphics.DrawLine(pen, new Point(0, 12), new Point(110, 12));
                lineStyles.Add(new LineStyle(item.ToString(), lineStyleBmp, item));
                lineStyleCmbx.Items.Add(item.ToString());

            }
            
            foreach (HatchStyle item in Enum.GetValues(typeof(HatchStyle)))
            {
                Bitmap hatchBmp = new Bitmap(100, 20);
                Graphics hatchGraphics = Graphics.FromImage(hatchBmp);
                hatchGraphics.FillRectangle(new HatchBrush(item, Color.Red, Color.White), 0, 0, hatchBmp.Width, hatchBmp.Height);
                fillStyles.Add(new FillStyle(item.ToString(), hatchBmp, item));
                fillStyleCmbx.Items.Add(item.ToString());
                
            }


            rectStripButton.Checked = true;
            selectedFigure = new Rect(new Point(), new Point());
            sizeCmbx.SelectedIndex = 1;
            lineStyleCmbx.SelectedIndex = 0;
            fillStyleCmbx.SelectedIndex = 0;
            paintContext.fillColor = Color.White;
            paintContext.penColor = Color.Black;

           // ChangeCulture(Thread.CurrentThread.CurrentUICulture);

        }

        private void sizeCmbx_DrawItem(object sender, DrawItemEventArgs e)
        {
            // Get the item.
            if (e.Index >= 0)
            {
                var item = sizeCmbx.Items[e.Index] as string;
                if (item == null)
                    return;
                Image image = lineSizes[e.Index].Image;
                // Get the coordinates to where to draw the image.
                int imageX = e.Bounds.X + 5;
                int imageY = e.Bounds.Y + ((e.Bounds.Height - image.Height) / 2);
                // Draw image
                e.Graphics.DrawImage(image, new Point(imageX, imageY));
                // Draw text
                e.Graphics.DrawString(item, this.Font, new SolidBrush(Color.Black),
                new PointF(65, e.Bounds.Y + 5));
            }
            
        }

        private void colorTsb_Click(object sender, EventArgs e)
        {
            paintContext.penColor = changeToolStripButtonColor(colorTsb); 
        }

        private void backgroundTsb_Click(object sender, EventArgs e)
        {
            paintContext.fillColor = changeToolStripButtonColor(backgroundTsb);
        }

        private void lineStyleCmbx_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index >= 0)
            {
                Image image = lineStyles[e.Index].Image;
                // Get the coordinates to where to draw the image.
                int imageX = e.Bounds.X + 5;
                int imageY = e.Bounds.Y + ((e.Bounds.Height - image.Height) / 2);
                // Draw image
                e.Graphics.DrawImage(image, new Point(imageX, imageY));
            }
        }



        private Color changeToolStripButtonColor(ToolStripButton button)
        {
            Color color = Color.White;
            if (colorDlg.ShowDialog() == DialogResult.OK)
            {
                color = colorDlg.Color;
                Bitmap colorBitmap = new Bitmap(16, 16);
                for (int i = 0; i < colorBitmap.Width; i++)
                {
                    for (int j = 0; j < colorBitmap.Height; j++)
                    {
                        colorBitmap.SetPixel(i, j, color);
                    }
                }
                button.Image = colorBitmap;
            }
            return color;
        }

        private void fillStyleCmbx_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index >= 0)
            {
                Image image = fillStyles[e.Index].Image;
                // Get the coordinates to where to draw the image.
                int imageX = e.Bounds.X + 5;
                int imageY = e.Bounds.Y + ((e.Bounds.Height - image.Height) / 2);
                // Draw image
                e.Graphics.DrawImage(image, new Point(imageX, imageY));
            }
        }

        #region ComboBoxes value choosing
        private void sizeCmbx_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox comboBox = (ComboBox)sender;
            paintContext.penSize = lineSizes[comboBox.SelectedIndex];
        }

        private void lineStyleCmbx_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox comboBox = (ComboBox)sender;
            paintContext.penStyle = lineStyles[comboBox.SelectedIndex];
        }

        private void fillStyleCmbx_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox comboBox = (ComboBox)sender;
            paintContext.fillStyle = fillStyles[comboBox.SelectedIndex];
        }
        #endregion

        #region Mouse-Down-Move-Up
        private void mainPanel_MouseDown(object sender, MouseEventArgs e)
        {
            if (textDrawing)
            {
                selectedFigure = textPlugin.getTextFigure();
                if (selectedFigure == null)
                {
                    return;
                }
            }
            if (e.Button.Equals(MouseButtons.Left)) {
                selectedFigure.startPoint = new Point(process(e.X), process(e.Y));
                drawing = true;
            }

            if (textDrawing)
            {
                mainPanel_MouseUp(sender, e);
            }
        }

        private void mainPanel_MouseMove(object sender, MouseEventArgs e)
        {
            mousePosTssl.Text = "x:" + e.X.ToString() + " y:" + e.Y.ToString();
            if (e.Button.Equals(MouseButtons.Left)) {
                selectedFigure.endPoint = new Point(process(e.X), process(e.Y));
            }
            mainPanel.Invalidate();
        }

        private void mainPanel_MouseUp(object sender, MouseEventArgs e)
        {
            selectedFigure.context = PaintContext.Copy(paintContext);
            shapes.Add(Drawable.Copy(selectedFigure));
            drawing = false;
            if (!undoToolStripButton.Enabled)
            {
                undoToolStripButton.Enabled = true;
            }
            if (redoToolStripButton.Enabled)
            {
                redoToolStripButton.Enabled = false;
            }
            shapesBuffer = new List<Drawable>(shapes);
        }
        #endregion

        private int process(float p) //taką sztuczką można zrobic
        {
            return (int)p / GRID_SIZE * GRID_SIZE;
        }

        private void minaPanel_Paint(object sender, PaintEventArgs e)
        {
            foreach (Drawable item in shapes)
            {
                item.draw(e.Graphics);
            }
            if (drawing)
            {
                selectedFigure.context = PaintContext.Copy(paintContext);
                selectedFigure.draw(e.Graphics);
            }
        }

        #region Figures Buttons
        private void rectStripButton_Click(object sender, EventArgs e)
        {
            changeFigure(sender, new Rect(new Point(), new Point()));
        }
        private void ellipseToolStripButton_Click(object sender, EventArgs e)
        {
            changeFigure(sender, new Ellipse(new Point(), new Point()));
        }

        private void lineToolStripButton_Click(object sender, EventArgs e)
        {
            changeFigure(sender, new Line(new Point(), new Point()));
        }

        private void pencilToolStripButton_Click(object sender, EventArgs e)
        {
            changeFigure(sender, new Pencil(new Point(), new Point()));
        }

        void textItem_Click(object sender, EventArgs e)
        {
            changeFigure(sender, null);
            textDrawing = true;
        }

        private void changeFigure(object sender, Drawable figure)
        {
            ToolStripButton checkedButton = (ToolStripButton)sender;
            uncheckedOtherButtons(checkedButton);
            checkedButton.Checked = true;
            selectedFigure = figure;
            textDrawing = false;
        }

        private void uncheckedOtherButtons(ToolStripButton sender)
        {
            foreach (ToolStripButton item in toolStrip2.Items)
            {
                if (item.Equals(sender)) continue;
                if (item.Checked)
                {
                    item.Checked = false;
                }
            }

            foreach (ToolStripButton item in toolStrip3.Items)
            {
                if (item.Equals(sender)) continue;
                if (item.Checked)
                {
                    item.Checked = false;
                }
            }
        }
        #endregion

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void clearToolStripMenuItem_Click(object sender, EventArgs e)
        {
            shapes.Clear();
            undoToolStripButton.Enabled = false;
            redoToolStripButton.Enabled = false;
            mainPanel.Invalidate();
        }

        private void undoToolStripButton_Click(object sender, EventArgs e)
        {
            redoToolStripButton.Enabled = true;
            shapes.Remove(shapes[shapes.Count - 1]);
            mainPanel.Invalidate();
            if (shapes.Count == 0)
            {
                undoToolStripButton.Enabled = false;
            }
            if (redoToolStripButton.Enabled)
            {
                redoToolStripButton.Enabled = true;
            }
        }

        private void redoToolStripButton_Click(object sender, EventArgs e)
        {
            shapes.Add(shapesBuffer[shapes.Count]);
            mainPanel.Invalidate();
            if (shapes.Count == shapesBuffer.Count)
            {
                redoToolStripButton.Enabled = false;
            }
            if (!undoToolStripButton.Enabled)
            {
                undoToolStripButton.Enabled = true;
            }
        }

        private void saveToolStripButton_Click(object sender, EventArgs e)
        {
            using (SaveFileDialog saveDlg = new SaveFileDialog())
            {
                saveDlg.InitialDirectory = ".";
                saveDlg.Filter = "Shape files (*.shapes)|*.shapes";
                saveDlg.RestoreDirectory = true;
                saveDlg.FileName = "MyShape.shapes";

                if (saveDlg.ShowDialog() == DialogResult.OK)
                {
                    Stream serializeStream = saveDlg.OpenFile();
                    if (serializeStream != null)
                    {
                        //save shapes
                        BinaryFormatter binaryFormatter = new BinaryFormatter();
                        binaryFormatter.Serialize(serializeStream, shapes);
                        serializeStream.Close();
                    }
                }
            }
        }

        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openDlg = new OpenFileDialog())
            {
                openDlg.InitialDirectory = ".";
                openDlg.Filter = "Shape files (*.shapes)|*.shapes|All files (*.*)|*.*";
                openDlg.RestoreDirectory = true;

                if (openDlg.ShowDialog() == DialogResult.OK)
                {
                    Stream deserializeStream = openDlg.OpenFile();
                    if (deserializeStream != null)
                    {
                        //restore shapes
                        BinaryFormatter binaryFormatter = new BinaryFormatter();
                        shapes = (List<Drawable>)binaryFormatter.Deserialize(deserializeStream);
                        shapesBuffer = new List<Drawable>(shapes);
                        undoToolStripButton.Enabled = true;
                        deserializeStream.Close();
                        mainPanel.Invalidate();

                    }
                }
            }    
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openToolStripButton_Click(sender, e);
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveToolStripButton_Click(sender, e);
        }

        private void pluginsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var openFileDialog = new OpenFileDialog();
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                Assembly assembly = Assembly.LoadFrom(openFileDialog.FileName);
                var types = assembly.GetTypes();
                foreach (var t in types)
                {
                    if (t.GetInterface(typeof(ITextPlugin).FullName) == null)
                    {
                        continue;
                    }
                    textPlugin = (ITextPlugin)Activator.CreateInstance(t);
                    ToolStripItem textItem = textPlugin.getToolStripItem();

                   /* string[] names = assembly.GetManifestResourceNames();
                    foreach (string name in names)
                    {
                        Console.WriteLine(name);
                    }*/
                    //load toolStripButtonImage
                    Stream stream = assembly.GetManifestResourceStream("TextPluginNamespace.text.png");
                    textItem.Image = Image.FromStream(stream);
                    stream.Close();
                    

                    textItem.Click += new EventHandler(textItem_Click);
                    toolStrip3.Items.Add(textItem);

                    //add loaded assembly to recognize it while deserialization
                    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(delegate { return assembly; });
                }
            }
        }

        #region Localization
        private void polishTsb_Click(object sender, EventArgs e)
        {
            ChangeCulture(new CultureInfo("pl-PL"));
        }

        private void englishTsb_Click(object sender, EventArgs e)
        {
            ChangeCulture(new CultureInfo("en"));
        }

        private void ChangeCulture(CultureInfo culture)
        {
            Thread.CurrentThread.CurrentUICulture = culture;
            ComponentResourceManager resources = new ComponentResourceManager(typeof(Paint));

            resources.ApplyResources(this, "$this", culture);
            toolTip.SetToolTip(this, resources.GetString("$this.ToolTip"));

            this.UpdateControlsCulture(this, resources, culture);

            if (culture.Name == "pl-PL")
            {
                polishTsb.Checked = true;
                englishTsb.Checked = false;
            }
            else
            {
                polishTsb.Checked = false;
                englishTsb.Checked = true;
            }

        }

        private void UpdateControlsCulture(Control control, ComponentResourceManager resourceProvider,
            CultureInfo culture)
        {
            control.SuspendLayout();
            resourceProvider.ApplyResources(control, control.Name, culture);

            foreach (Control ctrl in control.Controls)
            {
                //toolTip.SetToolTip(ctrl, resourceProvider.GetString(ctrl.Name + ".ToolTip"));
                UpdateControlsCulture(ctrl, resourceProvider, culture);
            }
            if (control is ComboBox)
            {
                return;
            }
            PropertyInfo property = control.GetType().GetProperty("Items");
            if (property != null)
            {
                foreach (ToolStripItem item in (IList)property.GetValue(control, null))
                {
                    UpdateToolStripItemsCulture(item, resourceProvider, culture);
                }
            }

            control.ResumeLayout(false);
        }

        private void UpdateToolStripItemsCulture(ToolStripItem item, ComponentResourceManager resourceProvider,
           CultureInfo culture)
        {
            resourceProvider.ApplyResources(item, item.Name, culture);

            if (item is ToolStripMenuItem)
            {
                foreach (ToolStripItem it in ((ToolStripMenuItem)item).DropDownItems)
                {
                    UpdateToolStripItemsCulture(it, resourceProvider, culture);
                }
            }
        }
        #endregion

    }
}
